package edu.wpi.cs509.network;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketException;

/**
 * Listens for client connections.
 * 
 * @author mreiter
 */
public class ConnectionListener implements Runnable {
	/** The port on which the server will listen for client connections. */
	static final int SERVER_PORT = 8102;
	
	/** The object that owns the connection listener. */
	private ConnectionOwner owner;
	
	/** The socket used to listen for client connections. */
	private ServerSocket serverSocket;
	
	/**
	 * Creates a new connection listener.
	 * 
	 * @param owner The object that owns the connection listener.
	 */
	public ConnectionListener(ConnectionOwner owner) {
		this.owner = owner;
	}
	
	/**
	 * Runs the connection listener loop. Does not return.
	 */
	@Override
	public void run() {
		// Create a socket that we will use to listen for client connections
		serverSocket = createServerSocket();
		
		System.out.println("Listening for connections...");
		
		while (!serverSocket.isClosed()) {
			try {
				// Accept the connection and create a new Connection
				// object to manage communications with the client
				new Connection(owner, serverSocket.accept());
			} catch (SocketException e) { // The listener was shut down
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * Stops listening for client connection.
	 */
	public synchronized void shutdown() {
		if (serverSocket != null) {
			try {
				serverSocket.close();
			} catch (IOException e) {}
		}
	}
	
	/**
	 * Creates a server socket used to listen for client connections.
	 * 
	 * @return The new server socket.
	 */
	private ServerSocket createServerSocket() {
		// Keep trying until the port is available
		while (true) {
			try {
				return new ServerSocket(SERVER_PORT);
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			// Wait 5 seconds in between attempts
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
		}
	}
}
